package com.hh.servlet.wxpay.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;

import javax.activation.MimetypesFileTypeMap;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import net.sf.json.JSONObject;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;



/**
 * 微信各种接口基本配置信息
 *
 * @author hewq
 */
public class WeixinService  {

    //访问后台的域名地址
    //微信appid
    public static final String appid = "wxeb8b68a5bc96b17d";
    //微信appscrect
    public static final String appScrect = "68249d217be1956f8e8c6f34bf80c5d7";
    //微信商户ID
    public static final String mch_id = "1637039060";
    //微信支付类型： h5支付
    public static final String trade_type = "JSAPI";
    
    public static final String clientIP = "36.150.110.180";

    //在微信商户平台设置的apikey
    public static final String apikey = "5a29f54e9bc34d5c99fc951927a63a0c";

    public static final String notifyUrl = "http://weimsoft.com/hisdemo/PayNotify";
   
    //编码
    public static final String paycharset = "UTF-8";
    //证书路径,注意应该填写绝对路径（仅退款、撤销订单时需要）
    //比如安装在D:/pkcs12/apiclient_cert.p12情况下，就可以写成如下语句"D:\\pkcs12\\apiclient_cert.p12";
    public static final String sslPath = "E:\\1575509571_20200219_cert\\apiclient_cert.p12";
    public static final String sslPawssword = "1575509571";

//	//酒店预订成功 (微信消息推送，用于推送模板,公众号对应的模板id)
//	public static final String BOOK_SUCCESS = "1AY3RmynoFHkblWejcZJqrCe1XR0fU3R3tepPj0q9yo";
//	
//	 //酒店预订失败(微信消息推送，用于推送模板,公众号对应的模板id)
//	public static final String BOOK_ERROR = "oa-ILNVs2Owtei5xscPB3XGTKWyD5CbaxCuGJ41Iw-4";

    public static String getRandomString(int length) { //length表示生成字符串的长度

        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }


    @SuppressWarnings("rawtypes")
    public static String createSign(String charSet, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + WeixinService.apikey);//xxxxxx换成你的API密钥
        String sign = MD5Util.MD5Encode(sb.toString(), charSet).toUpperCase();
        return sign;
    }


    /**
     * 解析xml,返回第一级元素键值对。如果第一级元素有子节点，则此节点的值是子节点的xml数据。
     *
     * @param strxml
     * @return
     * @throws JDOMException
     * @throws IOException
     */

    @SuppressWarnings({"unchecked", "rawtypes"})
    public static Map doXMLParse(String strxml) throws JDOMException, IOException {

        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");

        if (null == strxml || "".equals(strxml)) {

            return null;

        }

        Map m = new HashMap();

        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF8"));

        SAXBuilder builder = new SAXBuilder();

        Document doc = builder.build(in);

        Element root = doc.getRootElement();

        List list = root.getChildren();

        Iterator it = list.iterator();

        while (it.hasNext()) {

            Element e = (Element) it.next();

            String k = e.getName();

            String v = "";

            List children = e.getChildren();

            if (children.isEmpty()) {

                v = e.getTextNormalize();

            } else {

                v = getChildrenText(children);

            }

            m.put(k, v);

        }

        //关闭流

        in.close();

        return m;

    }

    /**
     * 获取子结点的xml
     *
     * @param children
     * @return String
     */

    @SuppressWarnings("rawtypes")
    public static String getChildrenText(List children) {

        StringBuffer sb = new StringBuffer();

        if (!children.isEmpty()) {

            Iterator it = children.iterator();

            while (it.hasNext()) {

                Element e = (Element) it.next();

                String name = e.getName();

                String value = e.getTextNormalize();

                List list = e.getChildren();

                sb.append("<" + name + ">");

                if (!list.isEmpty()) {

                    sb.append(getChildrenText(list));

                }

                sb.append(value);

                sb.append("</" + name + ">");

            }

        }

        return sb.toString();

    }

    /**
     * 将请求参数转换为xml格式的string
     *
     * @param parameters
     * @return
     */
    @SuppressWarnings("rawtypes")
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set es = parameters.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k)
                    || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }

    /**
     * 发送https请求
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param outputStr     提交的数据(xml)
     * @return 返回微信服务器响应的信息
     */
    public static String myhttpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());
            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();
            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod(requestMethod);
//            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            ce.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    @SuppressWarnings("rawtypes")
    public static String formUpload(String urlStr, Map<String, String> textMap,
                                    Map<String, String> fileMap) {
        String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符  
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn
                    .setRequestProperty("User-Agent",
                            "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text  
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();


                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                            "\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            // file  
            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    String contentType = new MimetypesFileTypeMap()
                            .getContentType(file);
                    if (filename.endsWith(".png")) {
                        contentType = "image/png";
                    }


                    if (contentType == null || contentType.equals("")) {
                        contentType = "application/octet-stream";
                    }

                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                            "\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"; filename=\"" + filename
                            + "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");

                    out.write(strBuf.toString().getBytes());

                    DataInputStream in = new DataInputStream(
                            new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // 读取返回数据  
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }


    @SuppressWarnings("rawtypes")
    public static String formUpload2(String urlStr, Map<String, String> textMap,
                                     Map<String, String> fileMap) {
        String res = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符  
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn
                    .setRequestProperty("User-Agent",
                            "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            conn.setRequestProperty("Content-Type",
                    "multipart/form-data; boundary=" + BOUNDARY);

            OutputStream out = new DataOutputStream(conn.getOutputStream());
            // text  
            if (textMap != null) {
                StringBuffer strBuf = new StringBuffer();
                Iterator iter = textMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();


                    if (inputValue == null) {
                        continue;
                    }
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                            "\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"\r\n\r\n");
                    strBuf.append(inputValue);
                }
                out.write(strBuf.toString().getBytes());
            }

            // file  
            if (fileMap != null) {
                Iterator iter = fileMap.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    File file = new File(inputValue);
                    String filename = file.getName();
                    String contentType = new MimetypesFileTypeMap()
                            .getContentType(file);
                    if (filename.endsWith(".png")) {
                        contentType = "image/png";
                    }


                    if (contentType == null || contentType.equals("")) {
                        contentType = "application/octet-stream";
                    }

                    StringBuffer strBuf = new StringBuffer();
                    strBuf.append("\r\n").append("--").append(BOUNDARY).append(
                            "\r\n");
                    strBuf.append("Content-Disposition: form-data; name=\""
                            + inputName + "\"; filename=\"" + filename
                            + "\"\r\n");
                    strBuf.append("Content-Type:" + contentType + "\r\n\r\n");

                    out.write(strBuf.toString().getBytes());

                    DataInputStream in = new DataInputStream(
                            new FileInputStream(file));
                    int bytes = 0;
                    byte[] bufferOut = new byte[1024];
                    while ((bytes = in.read(bufferOut)) != -1) {
                        out.write(bufferOut, 0, bytes);
                    }
                    in.close();
                }
            }

            byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
            out.write(endData);
            out.flush();
            out.close();

            // 读取返回数据  
            StringBuffer strBuf = new StringBuffer();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
            reader.close();
            reader = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return res;
    }

    /**
     * 返回加密的签名（js调用）
     *
     * @param jsapi_ticket
     * @param noncestr
     * @param timestamp
     * @param url
     * @return
     */
    public static String getSignature(String jsapi_ticket, String noncestr, String timestamp, String url) {
        String arr[] = {"jsapi_ticket", "noncestr", "timestamp", "url"};
        Arrays.sort(arr);
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].equals("jsapi_ticket")) {
                sb.append("jsapi_ticket=" + jsapi_ticket + "&");
            }
            if (arr[i].equals("noncestr")) {
                sb.append("noncestr=" + noncestr + "&");
            }
            if (arr[i].equals("timestamp")) {
                sb.append("timestamp=" + timestamp + "&");
            }
            if (arr[i].equals("url")) {
                sb.append("url=" + url + "&");
            }
        }
        String string1 = sb.toString();
        int count = string1.lastIndexOf("&");
        string1 = string1.substring(0, count);
        return SHA1.encode(string1);
    }

    public static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    /**
     * https://api.weixin.qq.com/cgi-bin/token
     * 获取accesstoken
     *
     * @return
     */
    public static String getAcessToken() {


        String accessToken = "";

        if (SelfEhcacheUtils.get("accesstoken") == null) {
            Map<String, String> params = new HashMap<String, String>();
            params.put("grant_type", "client_credential");
            params.put("appid", WeixinService.appid);
            params.put("secret", WeixinService.appScrect);

            String result = WeixinService.formUpload(
                    "https://api.weixin.qq.com/cgi-bin/token", params, null);
            JSONObject json = JSONObject.fromObject(result);
            accessToken = PublicUtil.null2String(json.get("access_token"));

            SelfEhcacheUtils.put("accesstoken", accessToken);

            //LOG.info("缓存没有accesstoken========="+accessToken);

        } else {
            accessToken = SelfEhcacheUtils.get("accesstoken") + "";
            //LOG.info("通过缓存拿accesstoken============"+accessToken);
        }

        //关闭后会报错
        //SelfSelfEhcacheUtils.shutdown();

        return accessToken;
    }

    /**
     * 获取jspi_tiket
     *
     * @return
     */
    public static String getTiket(String accessToken) {
        String jsapi_ticket = "";

        SelfEhcacheUtils.initCache("accessTokenCache");

        if (SelfEhcacheUtils.get("jsapi_ticket") == null) {
            Map<String, String> params2 = new HashMap<String, String>();
            params2.put("access_token", accessToken);
            params2.put("type", "jsapi");

            String result2 = WeixinService.formUpload(
                    "https://api.weixin.qq.com/cgi-bin/ticket/getticket", params2,
                    null);
            JSONObject json0 = JSONObject.fromObject(result2);
            jsapi_ticket = json0.get("ticket") + "";

            SelfEhcacheUtils.put("jsapi_ticket", jsapi_ticket);


        } else {
            jsapi_ticket = SelfEhcacheUtils.get("jsapi_ticket") + "";


        }

        //关闭后会报错
        //SelfEhcacheUtils.shutdown();

        return jsapi_ticket;
    }


    /**
     * 发起https请求并获取结果
     *
     * @param requestUrl    请求地址
     * @param requestMethod 请求方式（GET，POST）
     * @param outputStr     提交的数据
     * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
     */
    public static JSONObject httpRequest(String requestUrl,
                                         String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象，并使用我们制定的信任管理器初始化
            TrustManager[] tm = {new MyX509TrustManager()};
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());
            // 从上述SSLContext对象得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url
                    .openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);

            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod)) {
                httpUrlConn.connect();
            }
            // 当有数据需要提交时
            if (null != outputStr) {
                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 编码，防止乱码
                outputStream.write(outputStr.getBytes("utf-8"));
                outputStream.close();
            }
            // 将返还数据转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(
                    inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(
                    inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
            jsonObject = JSONObject.fromObject(buffer.toString());

        } catch (ConnectException ce) {
        } catch (Exception e) {
        }
        return jsonObject;
    }

}
